import re
import uiautomator2 as u2
import time, sys, os,io
import json
from lxml import etree
from PIL import Image
from loguru import logger
import pytesseract
import traceback
import subprocess
from PIL import ImageOps
import aircv as ac
import pyttsx3
import random
import datetime
import sqlite3
from multiprocessing import Lock,Value,Process
import tkinter as tk
from tkinter import ttk
#华为镜像源：https://repo.huaweicloud.com/repository/pypi/simple/
# python312 -m pip install -r requirements.txt -i https://repo.huaweicloud.com/repository/pypi/simple/
# 模拟器分辨率5400*960

class DevicePlayer:
    def __init__(self, device_id,device_name):
        self.device_id = device_id         # 模拟器编号
        self.device_name = device_name      # 模拟器名称
        self.device = None      #驱动实例
        self.now_position =  {'round': 0, 'future': '', 'direction': '','num': 0}   # 当前持仓
        self.next_position = {'round': 0, 'future': '', 'direction': '','num': 0}     # 下一持仓预计
        self.contract_list = ['小恒指05','恒指05']       # 合约列表
        self.strategy_list = [{'round': 1, 'future': '小恒指','direction': '', 'num': 1}, 
                              {'round': 2, 'future': '小恒指','direction': '',  'num': 2},
                            {'round': 3, 'future': '恒指', 'direction': '', 'num': 1},
                            {'round': 4, 'future': '恒指', 'direction': '', 'num': 2}, 
                            {'round': 5, 'future': '恒指','direction': '',  'num': 4},
                            {'round': 6, 'future': '恒指', 'direction': '', 'num': 8}]

    def connect_device(self):
        """连接模拟器"""
        logname = self.device_id + '_log.txt'
        logname = self.device_name+'_'+ self.device_id+ '_log.txt'
        logger.add(logname, encoding="utf-8")
        logger.info('准备连接设备 %s ...' % self.device_id)
        d = u2.connect(self.device_id)
        logger.info(f'连接设备 {self.device_id} ({self.device_name}) 成功!')
        self.device = d
        #self.login()           # 登录
        time.sleep(random.uniform(0.3, 5.5))
        #self.set_config()    # 初始配置
        self.transaction()     # 开始交易
        
        return d
    def disconnect_device(self):
        """断开与模拟器的连接"""
        if self.device is not None:
            self.device.close()
            logger.info(f'断开设备 {self.device_id} ({self.device_name}) 成功!\n')  

    
       

    def login(self):
        if self.device(text='登录交易').exists():
            
            time.sleep(0.5)
            self.device(resourceId="com.nngklblo.yitongda:id/username").set_text('S990008')
            self.device(resourceId="com.nngklblo.yitongda:id/psw").set_text('Icewxb2000')
            time.sleep(0.5)
            if not self.device(resourceId="com.nngklblo.yitongda:id/close_psw").info['checked']:
                self.device(resourceId="com.nngklblo.yitongda:id/close_psw").click()
            time.sleep(0.5)
            self.device(text='登录交易').click()
        else:
            logger.info(f'设备 {self.device_id} ({self.device_name}) 登录失败，不是登录页面!\n')

    def getStrategyinfo(self,last_position):
        """根据最后持单分析下一单策略"""
        for item in self.strategy_list:
            if last_position['future']==item['future'] and last_position['num']==item['num']:
                #找到了最后一次的平仓信息，要根据最后一次平仓信息来判断下一次持仓的策略
                if item['round']<6:
                    next_position=self.strategy_list[item['round']]
                    next_position['direction']=random.choice(['买','卖'])
                    logger.warning(f'{self.device_id}  {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}  当前分析最后持仓为：{last_position},下一步策略为：{next_position}')
                return next_position    
        return None # 没有找到对应策略
        #logger.warning(f'{self.device_id}  {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}  当前已有持仓为：{now_position},第{now_round}次')




    def check_guadan(self):
        """检查挂单情况"""
        time.sleep(random.uniform(0.3, 1.5))
        logger.info(f'设备 {self.device_id} ({self.device_name}) 准备检查挂单!')
        self.device(resourceId="com.nngklblo.yitongda:id/frag_order_guadan").click()  # 点击挂单选项卡
        time.sleep(random.uniform(0.3, 1.5))
        self.device.drag(43, 668, 510, 668, 0.03)   # 向右滑动鼠标，显示表格最左边数据
        time.sleep(random.uniform(0.3, 1.5))
        # 判断是否有挂单
        while True:
            
            try:
                if self.device(resourceId="com.nngklblo.yitongda:id/tv_item").exists():
                    
                    hymc=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/tv_item"]').get_text()  # 合约
                    wtj=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/tv_item"]').get_text()   # 委托价
                    wtsl=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/tv_item3"]').get_text()  # 委托数量
                    logger.info(f'设备 {self.device_id} ({self.device_name}) 挂单中，等待成交...')
                else:
                    logger.info(f'设备 {self.device_id} ({self.device_name}) 无挂单!')
                    return None
                time.sleep(random.uniform(2, 6))
            except Exception as e:
                logger.error(f'{self.device_id} {self.device_name}  {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}  获取挂单信息时发生错误{e}')
                return False
        

    def check_chicang(self):
        '''检查持仓情况'''
        
        logger.info(f'设备 {self.device_id} ({self.device_name}) 准备检查持单情况!')
        self.device(resourceId="com.nngklblo.yitongda:id/frag_order_chicang1").click()  # 点击持仓选项卡
        time.sleep(random.uniform(0.3, 1.5))
        self.device.drag(43, 668, 510, 668, 0.03)   # 向右滑动鼠标，显示表格最左边数据
        time.sleep(1)
        self.device.drag(212, 668, 510, 668, 0.03)   # 向右滑动鼠标，显示表格最左边数据
        time.sleep(1)
        
        
        if self.device(resourceId="com.nngklblo.yitongda:id/tv_itemname").info["text"] == "汇总(0)":        # 无持仓
            logger.info(f'设备 {self.device_id} ({self.device_name}) 暂无持仓!')
            self.now_position =  None   # 当前持仓改为空
            return None

        # 有持仓，则继续执行
        hymc=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/tv_itemname"]').get_text()  # 合约
        maimai=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/tv_item2"]').get_text()  # 买入卖出
        cjsl=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/tv_item4"]').get_text()    # 成交量

        self.device.drag(495, 737, 65, 737, 0.1)   # 向左滑动鼠标，显示表格右边数据
        yljc=self.device(resourceId="com.nngklblo.yitongda:id/tv_item_yingli").get_text()  # 盈利价差，点位数

        print(hymc,maimai,cjsl,yljc)

        direction=''
        if '卖' in maimai:
            direction='卖'
        if '买' in maimai:
            direction='买'
        
        if '小恒指' in hymc:
            future='小恒指'
        else:
            future='恒指'

        num=cjsl
        logger.warning(f'{self.device_id} :   合约 ：{future}  方向：{direction}  数量：{num}')
         
        now_position={'direction': direction, 'future': future, 'num': int(num)}
        for item in self.strategy_list:
            if future==item['future'] and int(num)==item['num']:
                #找到了当前持仓的策略
                now_position=item
                
                
        if now_position is not None:
            self.now_position=now_position
            self.now_position['direction']=direction
            logger.warning(f'{self.device_id}  {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}  当前已有持仓策略为：{self.now_position}')  
            # 转为监控状态
            while True:
                try:
                    yljc=0
                    time.sleep(random.randint(5,10))
                    
                    yljc=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/tv_item_yingli"]').get_text()  # 盈利价差，点位数
                    
                    print(f'{self.device_id} {self.device_name} {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}  当前持仓点差为:{yljc}')
                    if yljc is None or yljc=="" :  # 如果盈利价差为空表示持仓为空，则重新执行交易
                        #from playsound import playsound
                        self.transaction()
                        

                except Exception as e:
                    logger.error(f'{self.device_id}  {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}  执行持仓监控时发生错误{e}')
                    self.transaction()
                    return False


        else:
            logger.error(f'{self.device_id}  {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}  当前已有持仓为：{self.device_id} :   合约 ：{future}  方向：{direction}  数量：{num},无法匹配策略)')
            return False

    def transaction(self):
        """执行交易"""
        if not self.device(resourceId="com.nngklblo.yitongda:id/rb_jiaoyi").exists():  # 如果没有交易按钮，则转到交易页面
            self.device(resourceId="com.nngklblo.yitongda:id/search").click()
            time.sleep(random.randint(1,3))
            self.device(resourceId="com.nngklblo.yitongda:id/my").click()
            time.sleep(random.randint(1,3))
            self.device.click(249,131)
            time.sleep(random.randint(1,3))


        self.device(resourceId="com.nngklblo.yitongda:id/rb_jiaoyi").click()   # 点击交易按钮，转到交易页面
        time.sleep(random.randint(1,3))
        self.check_guadan() # 执行挂单检查，有挂单会转为监控状态，无挂单则返回


        if self.check_chicang() is None:  # 没有持仓
            logger.info(f'设备 {self.device_id} ({self.device_name}) 准备检查成交明细!')
            self.device(resourceId="com.nngklblo.yitongda:id/frag_order_chengjiao").click()  #                 点击成交明细选项卡
            time.sleep(random.randint(1,3))
            # 判断是否没有当日成交明细记录
            if self.device(resourceId="com.nngklblo.yitongda:id/cjtv1_item").exists():
                if self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv1_item"]').info["text"] == "汇总(0)":
                    self.next_position = self.strategy_list[0]
                    self.next_position['direction']=random.choice(['买','卖'])
                    logger.info(f'设备 {self.device_id} ({self.device_name}) 暂无成交明细!,暂时按第一手下单 {self.strategy_list[0]}')
                    self.transaction_order()  # 执行交易
                    return False
               

            self.device.drag(326, 481, 321, 800, 0.05)   # 向下滑动鼠标，显示表格最上边数据
            time.sleep(0.5)
            self.device.drag(330, 485, 325, 798, 0.05)   
            time.sleep(0.5)
            self.device.drag(333, 480, 330, 795, 0.05)   
            time.sleep(0.5)



            self.device.drag(160, 778, 510, 778, 0.05)   # 向右滑动鼠标，显示表格最左边数据
            time.sleep(0.5)
            self.device.drag(160, 778, 510, 778, 0.05)   # 向右滑动鼠标，显示表格最左边数据
            time.sleep(0.5)
            self.device.drag(160, 778, 510, 778, 0.05)   # 向右滑动鼠标，显示表格最左边数据
            time.sleep(0.5)
          
                
            hymc=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv1_item"]').get_text()  # 合约
            kp=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv8_item"]').get_text()    # 开平
            direction=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv2_item"]').get_text() # 买卖
            cjj=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv3_item"]').get_text()   # 成交价

            if kp=='平仓':
                pcsl=1
                i=2
                while True:
                    try:
                        if self.device.xpath('(//*[@resource-id="com.nngklblo.yitongda:id/cjtv8_item"])['+str(i) +']').get_text()=='平仓':    # 这个序号只是屏幕可见区域的排序，滑动屏幕后就会重新从头排，这里代码需要调整
                            pcsl=pcsl+1    # 平仓数量也不一定是1，要根据实际行数来获取，同上有屏幕显示区域问题
                            i=i+1
                        else:
                            break
                    except Exception as e:
                        break
                self.device.drag(495, 538, 65, 538, 0.05)
                time.sleep(1)
                sxf=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv6_item"]').get_text()   # 手续费
                pcyk=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv7_item"]').get_text()  # 平仓盈亏
                cjsl=int(self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv4_item"]').get_text())  # 成交数量
                for j in range(2,i):
                    try:
                        cjsl=cjsl+int(self.device.xpath('(//*[@resource-id="com.nngklblo.yitongda:id/cjtv4_item"])['+str(j) +']').get_text())
                        if j>=6: # 需要将明细往下滑动，以便获取全部的成交明细
                            self.device.drag(300, 760, 300, 465, 0.05)
                            time.sleep(1)
                    except Exception as e:
                        logger.error(f'{self.device_id}  {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}  获取成交明细中成交数量时发生错误{e}')
                        return False
                
                self.device.drag(495, 538, 65, 538, 0.1)  # 向左滑动鼠标，显示表格右边数据
                time.sleep(1)
                sj=self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/cjtv5_item"]').get_text()    # 时间
                pcyk=float(pcyk)
                if '小恒指' in hymc:
                    future='小恒指'
                else:
                    future='恒指'

                # 成交数量需要累计计算的，这里还没有计算，需要在后面加上
                num=int(cjsl)
               
              

                print('成交平仓数据：',hymc,kp,direction,pcsl,pcyk,sj)
                if hymc=='' and direction=='':
                    logger.warning(f'设备 {self.device_id} ({self.device_name}) 无当日成交记录...程序退出')
                    return False

                last_position={'direction': direction, 'future': future, 'num': num}

                self.next_position = None
                if pcyk>0:
                    logger.info(f'设备 {self.device_id} ({self.device_name}) {hymc} {kp} {pcsl} {pcyk} {sj} 平仓盈利')

                    self.next_position=self.strategy_list[0] # 返回第一次执行策略
                    self.next_position['direction']=random.choice(['买','卖'])
                    print(self.next_position)
                else:
                    self.next_position = self.getStrategyinfo(last_position)
                    logger.info(f'设备 {self.device_id} ({self.device_name}) {hymc} {kp} {pcsl} {pcyk} {sj} 平仓亏损')
                    print(self.next_position)

                if self.next_position  is not None:
                    self.transaction_order()
                    


        else:                                                                                     # 有持仓
            logger.info(f'设备 {self.device_id} ({self.device_name}) 有持仓!')
            self.check_chicang()

        return
    def remove_digits(self, s):
        # 移除字符串中的数字
        return re.sub(r'\d', '', s)
    def transaction_order(self):
        """下单操作"""
        logger.info(f'设备 {self.device_id} ({self.device_name}) 准备下单!')
        #点击合约选择框
        time.sleep(random.uniform(0.3, 1.5))
        self.device(resourceId="com.nngklblo.yitongda:id/contract_name_rest").click()
        time.sleep(random.uniform(0.3, 1.5))
        
        if self.next_position['future']=='小恒指':
            if '小恒指' == self.remove_digits(self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/item_textview"]').get_text()):
                self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/item_textview"]').click()
            elif '小恒指' == self.remove_digits(self.device.xpath('(//*[@resource-id="com.nngklblo.yitongda:id/item_textview"])[2]').get_text()):
                self.device.xpath('(//*[@resource-id="com.nngklblo.yitongda:id/item_textview"])[2]').click()

        if self.next_position['future']=='恒指':
            if '恒指' == self.remove_digits(self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/item_textview"]').get_text()):
                self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/item_textview"]').click()
            elif '恒指' == self.remove_digits(self.device.xpath('(//*[@resource-id="com.nngklblo.yitongda:id/item_textview"])[2]').get_text()):
                self.device.xpath('(//*[@resource-id="com.nngklblo.yitongda:id/item_textview"])[2]').click()

        time.sleep(random.uniform(0.3, 1.5))
        #打开快速下单对话框
        self.device(resourceId="com.nngklblo.yitongda:id/stop_profit_loss").click()
        time.sleep(random.uniform(0.3, 1.5))

        #判断合约是否一致
        if self.next_position['future']!=self.remove_digits(self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/contract_name"]').get_text()):
            logger.error(f'设备 {self.device_id} ({self.device_name}) 合约不匹配!')
            return
        
        #设置方向
        if self.next_position['direction']=='买':
            if self.device(resourceId="com.nngklblo.yitongda:id/tv_buyortell").get_text()=='买入':
                pass
            else:
                self.device(resourceId="com.nngklblo.yitongda:id/tv_buyortell").click()
        elif self.next_position['direction']=='卖':
            if self.device(resourceId="com.nngklblo.yitongda:id/tv_buyortell").get_text()=='卖出':
                pass
            else:
                self.device(resourceId="com.nngklblo.yitongda:id/tv_buyortell").click()

         
        #设置手数
        self.device(resourceId="com.nngklblo.yitongda:id/et_shoushu").set_text(str(self.next_position['num']))
        time.sleep(random.uniform(0.7, 2.5))
        #设置价格
        now_price=int(self.device(resourceId="com.nngklblo.yitongda:id/tv_lastprice").get_text())
        if self.next_position['direction']=='买':
            self.device(resourceId="com.nngklblo.yitongda:id/et_price").set_text(str(now_price + 500))
        elif self.next_position['direction']=='卖':
            self.device(resourceId="com.nngklblo.yitongda:id/et_price").set_text(str(now_price - 500))
        time.sleep(random.uniform(2, 3))
        #self.device(resourceId="com.nngklblo.yitongda:id/bt_sure").click()  # 点击确定按钮  
                

      
        time.sleep(random.uniform(0.3, 1.5))
        self.device(resourceId="com.nngklblo.yitongda:id/iv_close").click()  # 关闭快速下单对话框
        time.sleep(random.uniform(2, 5))
        
        self.check_guadan()  # 检查当前挂单信息
        self.check_chicang()  # 检查当前持仓信息





            
            





    def set_config(self):
        """止盈止损点位与自选合约设置"""
        while True:  # 循环取消所有自选，批量取消会导致页面无响应，所以只能一次取消一个
            time.sleep(1)
            #点击搜索按钮，
            self.device(resourceId="com.nngklblo.yitongda:id/search").click()
            time.sleep(1)
            # 判断是否有自选按钮出现
            if self.device(resourceId="com.nngklblo.yitongda:id/my").exists():
                logger.info(f'设备 {self.device_id} ({self.device_name}) 有自选!\n')
                self.device(resourceId="com.nngklblo.yitongda:id/my").click()
                time.sleep(1)
                screenshot = self.device.screenshot()
                screenshot = self.device.screenshot()  # 获取截图（PIL Image 对象）
                r, g, b = screenshot.getpixel((496, 133))  # 直接从 PIL Image 对象中获取像素颜色

                print(f"Color at (496, 133): RGB({r}, {g}, {b})")
                if r==68 and g==68 and b==68:  # 没有自选合约了
                    # 没有自选合约，开始选择
                    self.device(resourceId="com.nngklblo.yitongda:id/et_search").set_text(self.contract_list[0])
                    time.sleep(1)
                    self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/iv_collect"]').click()    # 点击设置为自选
                    time.sleep(1)
                    self.device(resourceId="com.nngklblo.yitongda:id/et_search").set_text(self.contract_list[1])
                    time.sleep(1)
                    self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/iv_collect"]').click()    # 点击设置为自选
                    time.sleep(1)

                    self.device(resourceId="com.nngklblo.yitongda:id/back").click()
                    break

                else:
                    logger.info(f'设备 {self.device_id} ({self.device_name}) 有自选!')               
                    self.device.xpath('//*[@resource-id="com.nngklblo.yitongda:id/iv_collect"]').click()    # 取消第一个自选
                    time.sleep(1)
                    self.device(resourceId="com.nngklblo.yitongda:id/back").click()
                    
                    
                            

                    
        

if __name__ == '__main__':
    root = tk.Tk()
    root.title("账号列表")
    tree_rowids=[]
    columns = ('行编号','账号','类型', '姓名','脚本','状态','账户金额','成交指数','浮动盈亏','平仓盈亏','手续费','轮/次','更新时间')
    tree = ttk.Treeview(root,columns=columns, show='headings')

    
    player = DevicePlayer("emulator-5572","bsk01")
    p = Process(target=player.connect_device)
    p.daemon = True  # 注释掉或设置为 False
    p.start()
    
    '''
    player1 = DevicePlayer("emulator-5570", "bsk02")
    p1 = Process(target=player1.connect_device)
    p1.daemon = True  # 注释掉或设置为 False
    p1.start()
    
        

    player2 = DevicePlayer("emulator-5574", "bsk03")
    p2 = Process(target=player2.connect_device)
    p2.daemon = True  # 注释掉或设置为 False
    p2.start()
    '''
    
    root.mainloop()
        

   

   
